﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Effects
{
    /// <summary>
    /// This public class creates a frame overlay over another texture
    /// </summary>
    public class FrameOverlay : Overlay
    {

        /// <summary>
        /// Contains all the versions of frame overlays
        /// The recommended method to creating overlays is to use the static factory method and let the constructors do their work
        /// </summary>
        protected static List<FrameOverlay> frames = new List<FrameOverlay>();

        /// <summary>
        /// The color of the frame to draw
        /// </summary>
        protected Color _color;

        /// <summary>
        /// The fatness of the frame
        /// </summary>
        protected int _fatness;

        /// <summary>
        /// Creates or returns an existing matching overlay that you can then draw over another entity later
        /// </summary>
        /// <param name="device">Device on which to create the surface</param>
        /// <param name="positionSize">Position and size of the overlay</param>
        /// <param name="color">Color of the overlay</param>
        public static FrameOverlay get(GraphicsDevice graphics, Rectangle positionSize, Color color)
        {
            foreach (FrameOverlay overlay in frames)
            {
                if (overlay._positionSize == positionSize && overlay._color == color)
                {
                    return overlay;
                }
            }
            FrameOverlay newFrameOverlay = new FrameOverlay(graphics, positionSize, color);
            frames.Add(newFrameOverlay);
            return newFrameOverlay;
        }

        /// <summary>
        /// Creates or returns an existing matching overlay that you can then draw over another entity later
        /// </summary>
        /// <param name="device">Device on which to create the surface</param>
        /// <param name="positionSize">Position and size of the overlay</param>
        /// <param name="color">Color of the overlay</param>
        /// <param name="fatness">Fatness the overlay</param>
        public static FrameOverlay get(GraphicsDevice graphics, Rectangle positionSize, Color color, int fatness)
        {
            foreach (FrameOverlay overlay in frames)
            {
                if (overlay._positionSize == positionSize && overlay._color == color && overlay._fatness == fatness)
                {
                    return overlay;
                }
            }
            FrameOverlay newFrameOverlay = new FrameOverlay(graphics, positionSize, color, fatness);
            frames.Add(newFrameOverlay);
            return newFrameOverlay;
        }

        /// <summary>
        /// Creates an overlay that you can then draw over another entity later
        /// </summary>
        /// <param name="device">Device on which to create the surface</param>
        /// <param name="positionSize">Position and size of the overlay</param>
        /// <param name="color">Color of the overlay</param>
        public FrameOverlay(GraphicsDevice device, Rectangle positionSize, Color color)
        {

            //Setup the overlay in memory
            this._positionSize = positionSize;
            this._color = color;
            this._fatness = 1;

            //Draw the overlay
            this.refreshOverlay(device);

        }

        /// <summary>
        /// Creates an overlay that you can then draw over another entity later
        /// </summary>
        /// <param name="device">Device on which to create the surface</param>
        /// <param name="positionSize">Position and size of the overlay</param>
        /// <param name="color">Color of the overlay</param>
        /// <param name="fatness">Fatness the overlay</param>
        public FrameOverlay(GraphicsDevice device, Rectangle positionSize, Color color, int fatness)
        {

            //Setup the overlay in memory
            this._positionSize = positionSize;
            this._color = color;
            this._fatness = fatness;

            //Draw the overlay
            this.refreshOverlay(device);

        }

        /// <summary>
        /// Refreshes the overlay in memory. Do it after you change something on the overlay such as the fatness or size
        /// </summary>
        public void refreshOverlay(GraphicsDevice device)
        {

            //Create a buffer on which to draw
            this._texture = new Texture2D(device, _positionSize.Width, _positionSize.Height);
            Color[] pixelData = new Color[_positionSize.Width * _positionSize.Height];

            //The top and bottom are easy to compute, they are at 0 + line * width or lenght - line * width
            for (int x = 0; x < this._fatness * _positionSize.Width; x++)
            {
                pixelData[x] = this._color;
            }
            for (int x = (_positionSize.Width * _positionSize.Height) - (this._fatness * _positionSize.Width); x < (_positionSize.Width * _positionSize.Height); x++)
            {
                pixelData[x] = this._color;
            }

            //For the sides, you have to use a combination of width and heigh to plot and draw using the fatness
            //Start by compiling the heights to work with, skip the fatness in Y, it was drawn with the Xs
            for (int y = 0 + this._fatness; y < _positionSize.Height - this._fatness; y++)
            {
                //Compute the Xs by keeping only what is within the fatness
                for (int x = 0; x < this._fatness; x++)
                {
                    pixelData[y * _positionSize.Width + x] = this._color;
                }
                for (int x = _positionSize.Width - this._fatness; x < _positionSize.Width; x++)
                {
                    pixelData[y * _positionSize.Width + x] = this._color;
                }
            }

            //Save the pixeldata
            this._texture.SetData<Color>(pixelData);

        }

        /// <summary>
        /// Draws the entity on the screen
        /// </summary>
        /// <param name="spriteBatch">spriteeBatch on which to draw the entity</param>
        public void Draw(SpriteBatch spriteBatch)
        {
            if (this._visible == false) { return; }
            spriteBatch.Draw(this._texture, this._positionSize, new Color(1f, 1f, 1f, 1f));
        }

    }
}
